import bpy, mathutils
from bpy.props import *


displayPanelSetPerso = False
displayPanelNavMesh = False
displayPanelElements = False
displayPanelAnimations = False

########################################
#   Store properties in active scene   #
########################################

def initSceneProperties(scn):
    bpy.types.Scene.RunAnimationName = bpy.props.StringProperty(name="Run ", description="Name of the running animation.")
    bpy.types.Scene.WalkAnimationName = bpy.props.StringProperty(name="Walk ", description="Name of the walking animation.")
    bpy.types.Scene.IdleAnimationName = bpy.props.StringProperty(name="Idle ", description="Name of the idle animation.")
    bpy.types.Scene.ZombieName = bpy.props.StringProperty(name="Zombie ", description="Name of the zombie object.")
    bpy.types.Scene.HumanName = bpy.props.StringProperty(name="Human ", description="Name of the human object.")
    bpy.types.Scene.CityName = bpy.props.StringProperty(name="City name ", description="Name of the city object.")
    bpy.types.Scene.CityScale = FloatProperty(name = "Scale ", description = "Extend the preset positions of the marks to match better with the mesh.", default= 1, min = 0.01, max = 20)
    scn['CityScale'] = 1
    bpy.types.Scene.CitySize = EnumProperty(name = "Size", items=(('0','Very Small','x:y =<250'),('1','Small','250 < x:y =<500'),('2','Medium','500 < x:y =<1000'),('3','Large','x:y >1000')))
    bpy.types.Scene.CityMaxSlope = IntProperty(name = "Max Slope ", description = "Max angle for slopes", min = 0, max = 90)
    scn['CityMaxSlope'] = 45
    bpy.types.Scene.NbZombie = IntProperty(name = "Nb zombies ", description = "Number of zombies to create", min = 0, max = 70)
    scn['NbZombie'] = 2
    bpy.types.Scene.NbHuman = IntProperty(name = "Nb humans ", description = "Number of zombies to create", min = 0, max = 500)
    scn['NbHuman'] = 30
    bpy.types.Scene.NbHumanMark = IntProperty(name = "Nb human mark ", description = "Number of mark where humans will be created.", min = 1, max = 15)
    scn['NbHumanMark'] = 4
    bpy.types.Scene.NbZombieMark = IntProperty(name = "Nb zombie mark", description = "Number of mark where zombies will be created.", min = 1, max = 15)
    scn['NbZombieMark'] = 4
    bpy.types.Scene.ZombieVelocity = FloatProperty(name = "Running speed ", description = "How fast the zombies will run.", default= 3, min = 0.01, max = 50)
    scn['ZombieVelocity'] = 3
    
    return
    
initSceneProperties(bpy.context.scene)

#####################
#   Layout panel    #
#####################

class LayoutPanel(bpy.types.Panel):
    bl_label = "Crowd simulation"
    bl_space_type = "VIEW_3D"
    bl_region_type = "TOOL_PROPS"
    
    def draw(self, context):
        
        #global displayScale
        
        layout = self.layout
        
        ##########################################################
        #                       ANIMATION                        #
        ##########################################################
        
        animationBox = layout.box()
        nameRow = animationBox.row()
        
        nameRow.alignment = "LEFT"
        nameRow.operator("action.button", text = "1. Animations names :", icon="SEQUENCE", emboss=False).action="animation"
        if displayPanelAnimations == True:
            walkingRow = animationBox.row()
            walkingRow.prop(context.scene, 'WalkAnimationName', icon ="OUTLINER_DATA_FONT")
            runningRow = animationBox.row()
            runningRow.prop(context.scene, 'RunAnimationName', icon ="OUTLINER_DATA_FONT")
            idleRow = animationBox.row()
            idleRow.prop(context.scene, 'IdleAnimationName', icon ="OUTLINER_DATA_FONT")
           
        ###############################################################
        #                       SET CHARACTERS                        #
        ###############################################################
        
        settingsPersoBox = layout.box()
        nameRow = settingsPersoBox.row()
        
        nameRow.alignment = "LEFT"
        nameRow.operator("action.button", text = "2. Set characters :", icon="POSE_DATA", emboss=False).action="setPerso"
        if displayPanelSetPerso == True:
            zombieBox = settingsPersoBox.box()
            zombieRow = zombieBox.row()
            zombieRow.prop(context.scene, 'ZombieName', icon ="OUTLINER_DATA_FONT")
            zombieRow = zombieBox.row()
            zombieRow.prop(context.scene, 'ZombieVelocity')
            zombieRow = zombieBox.row()
            zombieRow.operator("set_perso.button", text = "Set zombie", icon="LOGIC").action="zombie"
            NbZombieRow = zombieBox.row()
            NbZombieRow.prop(context.scene, 'NbZombie', icon ="OUTLINER_DATA_FONT")
            
            humanBox = settingsPersoBox.box()
            humanRow = humanBox.row()
            humanRow.prop(context.scene, 'HumanName', icon ="OUTLINER_DATA_FONT")
            humanRow = humanBox.row()
            humanRow.operator("set_perso.button", text = "Set human", icon="LOGIC").action="human"
            NbHumanRow = humanBox.row()
            NbHumanRow.prop(context.scene, 'NbHuman', icon ="OUTLINER_DATA_FONT")
            
            
            
        ################################################################
        #                       NAVIGATION MESH                        #
        ################################################################
        
        navMeshBox = layout.box()
        nameRow = navMeshBox.row()
        
        nameRow.alignment = "LEFT"
        nameRow.operator("action.button", text = "3. Navigation mesh :", icon="URL", emboss=False).action="navMesh"
        if displayPanelNavMesh == True:
            cityBox = navMeshBox.box()
            cityRow = cityBox.row()
            cityRow.prop(context.scene, 'CityName', icon ="OUTLINER_DATA_FONT")
            scaleRow = cityBox.row()
            scaleRow.prop(context.scene, 'CityScale')
            applyRow = cityBox.row()
            applyRow.operator("apply_scale.button", text = "Apply scale", icon="MANIPUL")
            
            navBox = navMeshBox.box()
            sizeRow = navBox.row()
            sizeRow.label("Generate navigation mesh :",icon ="WORLD")
            sizeRow = navBox.row()
            sizeRow.prop(context.scene, 'CitySize', expand = True)
            slopeRow = navBox.row()
            slopeRow.prop(context.scene, 'CityMaxSlope', icon ="OUTLINER_DATA_FONT", expand = True)
            navMeshRow = navBox.row()
            navMeshRow.operator("nav_mesh.button", text = "Build navigation mesh", icon="FORCE_TEXTURE").action="build"
            delNavMeshRow = navBox.row()
            delNavMeshRow.operator("nav_mesh.button", text = "Delete navigation mesh", icon="CANCEL").action="delete"
        
        ###############################################################
        #                       BASIC ELEMENTS                        #
        ###############################################################
        
        elementBox = layout.box()
        nameRow = elementBox.row()
        
        nameRow.alignment = "LEFT"
        nameRow.operator("action.button", text = "4. Required elements :", icon="SCENE_DATA", emboss=False).action="elements"
        if displayPanelElements == True:
            essentialBox = elementBox.box()
            essentialRow = essentialBox.row()
            essentialRow.label("Essentials :",icon="EXTERNAL_DATA")
            essentialRow = essentialBox.row()
            essentialRow.operator("set_essentials.button", text = "Set essentials", icon="LOGIC")
            
            cameraBox = elementBox.box()
            cameraRow = cameraBox.row()
            cameraRow.label("Camera :",icon="CAMERA_DATA")
            cameraRow = cameraBox.row()
            cameraRow.operator("set_elements.button", text = "Set camera", icon="LOGIC").action="camera"
            
            HumanMarkBox = elementBox.box()
            NbHumanMarkRow = HumanMarkBox.row()
            NbHumanMarkRow.label("Generation human mark :",icon ="MOD_ARMATURE")
            NbHumanMarkRow = HumanMarkBox.row()
            NbHumanMarkRow.prop(context.scene, 'NbHumanMark')
            HumanMarkRow = HumanMarkBox.row()
            HumanMarkRow.operator("set_elements.button", text = "Generate human marks", icon="OBJECT_DATA").action="human"
            
            ZombieMarkBox = elementBox.box()
            NbZombieMarkRow = ZombieMarkBox.row()
            NbZombieMarkRow.label("Generation zombie mark :",icon ="OUTLINER_OB_ARMATURE")
            NbZombieMarkRow = ZombieMarkBox.row()
            NbZombieMarkRow.prop(context.scene, 'NbZombieMark')
            ZombieMarkRow = ZombieMarkBox.row()
            ZombieMarkRow.operator("set_elements.button", text = "Generate zombie marks", icon="OBJECT_DATA").action="zombie"
            
      
#******************************************#
#**######################################**#
#**#      Panel functions               #**#
#**######################################**#
#******************************************#
    
##################################
#   Class panel boxes buttons    #
##################################
class OBJECT_OT_Button(bpy.types.Operator):
    bl_idname = "action.button"
    bl_label = "Button"
    
    action = bpy.props.StringProperty()
    
    def execute(self, context): 
        global displayPanelSetPerso
        global displayPanelNavMesh
        global displayPanelElements
        global displayPanelAnimations
        
        if self.action == "setPerso" and displayPanelSetPerso == True:
            displayPanelSetPerso = False
        elif self.action == "setPerso":
            displayPanelSetPerso = True
        
        if self.action == "navMesh" and displayPanelNavMesh == True:
            displayPanelNavMesh = False
        elif self.action == "navMesh":
            displayPanelNavMesh = True
        
        if self.action == "elements" and displayPanelElements == True:
            displayPanelElements = False
        elif self.action == "elements":
            displayPanelElements = True
        
        if self.action == "animation" and displayPanelAnimations == True:
            displayPanelAnimations = False
        elif self.action == "animation":
            displayPanelAnimations = True
               
        return {'FINISHED'}

#######################################
#   Class panel essentials buttons    #
#######################################
class OBJECT_OT_Button(bpy.types.Operator):
    bl_idname = "set_essentials.button"
    bl_label = "Button"
    
    def execute(self, context):
        
        generateEssentials()
            
        return {'FINISHED'}
    
####################################
#   Class panel elemnts buttons    #
####################################
class OBJECT_OT_Button(bpy.types.Operator):
    bl_idname = "set_elements.button"
    bl_label = "Button"
    
    action = bpy.props.StringProperty()
    
    def execute(self, context):
        
        if self.action == "camera":
            createCamera()
        elif self.action == "human":
            generatePopMark("human")
        elif self.action == "zombie":
            generatePopMark("zombie")
            
        return {'FINISHED'}
    
################################################
#   Class panel set navigation mesh buttons    #
################################################
class OBJECT_OT_Button(bpy.types.Operator):
    bl_idname = "nav_mesh.button"
    bl_label = "Button"
    
    action = bpy.props.StringProperty()
    
    def execute(self, context): 
        Size = bpy.context.scene.CitySize
        Slope = bpy.context.scene.CityMaxSlope
        City = bpy.context.scene.CityName
        
        if self.action == "build":
            
            bpy.ops.object.select_all(action='DESELECT')
            
            ob = bpy.data.objects.get('Navmesh')
            if ob != None:
                bpy.data.objects.get('Navmesh').select = True
                
            bpy.ops.object.delete()
            
            ob = bpy.data.objects.get(City)
            if ob != None:
                bpy.data.objects.get(City).select = True
                
            if Size == "0":
                bpy.context.scene.game_settings.recast_data.cell_size = 0.10
                bpy.context.scene.game_settings.recast_data.cell_height = 0.10
                bpy.context.scene.game_settings.recast_data.verts_per_poly = 3
                bpy.context.scene.game_settings.recast_data.edge_max_len = 20
                bpy.context.scene.game_settings.recast_data.slope_max = Slope * 0.017453
                bpy.ops.mesh.navmesh_make()
            if Size == "1":
                bpy.context.scene.game_settings.recast_data.cell_size = 0.33
                bpy.context.scene.game_settings.recast_data.cell_height = 0.33
                bpy.context.scene.game_settings.recast_data.verts_per_poly = 3
                bpy.context.scene.game_settings.recast_data.edge_max_len = 20
                bpy.context.scene.game_settings.recast_data.slope_max = Slope * 0.017453
                bpy.ops.mesh.navmesh_make()
            elif Size == "2":
                bpy.context.scene.game_settings.recast_data.cell_size = 0.66
                bpy.context.scene.game_settings.recast_data.cell_height = 0.66
                bpy.context.scene.game_settings.recast_data.verts_per_poly = 3
                bpy.context.scene.game_settings.recast_data.edge_max_len = 20
                bpy.context.scene.game_settings.recast_data.slope_max = Slope * 0.017453
                bpy.ops.mesh.navmesh_make()
            elif Size == "3":
                bpy.context.scene.game_settings.recast_data.cell_size = 1
                bpy.context.scene.game_settings.recast_data.cell_height = 1
                bpy.context.scene.game_settings.recast_data.verts_per_poly = 3
                bpy.context.scene.game_settings.recast_data.edge_max_len = 20
                bpy.context.scene.game_settings.recast_data.slope_max = Slope * 0.017453
                bpy.ops.mesh.navmesh_make()
            
            # Set the logic objects to the city
            bpy.ops.object.select_all(action='DESELECT')
            
            ob = bpy.data.objects.get(City)
            if ob != None:
                bpy.data.objects.get(City).select = True
                bpy.context.scene.objects.active = bpy.data.objects[City]
                
                if len(bpy.context.active_object.game.sensors) == 0:
                    # LOGIC OBJECTS
                        # SENSORS
                    bpy.ops.logic.sensor_add(type='ALWAYS', name="Clean Objectives_SEN", object="")
                    bpy.context.active_object.game.sensors['Clean Objectives_SEN'].use_pulse_true_level = True
                    bpy.context.active_object.game.sensors['Clean Objectives_SEN'].frequency = 5000
                    
                        # CONTROLLERS
                    bpy.ops.logic.controller_add(type='PYTHON', name="Clean Objectives_CONT", object="")
                    bpy.context.active_object.game.controllers["Clean Objectives_CONT"].mode = "MODULE"
                    bpy.context.active_object.game.controllers["Clean Objectives_CONT"].module = "Tools.CleanObjectives"
                    bpy.context.active_object.game.controllers["Clean Objectives_CONT"].use_priority = True
                    bpy.context.active_object.game.controllers["Clean Objectives_CONT"].link(bpy.context.active_object.game.sensors['Clean Objectives_SEN'])
            
        elif self.action == "delete":
        
            bpy.ops.object.select_all(action='DESELECT')
            
            ob = bpy.data.objects.get('Navmesh')
            if ob != None:
                bpy.data.objects.get('Navmesh').select = True
                
            bpy.ops.object.delete()

            
        return {'FINISHED'}
    
###########################################
#   Class panel set characters buttons    #
###########################################
class OBJECT_OT_Button(bpy.types.Operator):
    bl_idname = "set_perso.button"
    bl_label = "Button"
    
    action = bpy.props.StringProperty()
    
    def execute(self, context): 
        ZombieName = bpy.context.scene.ZombieName
        HumanName = bpy.context.scene.HumanName
        
        if self.action == "zombie" and ZombieName != "":
            setCharacter(ZombieName, "zombie")
            
        if self.action == "human" and HumanName != "":
            setCharacter(HumanName, "human")
            
        return {'FINISHED'}

############################################
#   Class panel set apply scale buttons    #
############################################
class OBJECT_OT_Button(bpy.types.Operator):
    bl_idname = "apply_scale.button"
    bl_label = "Button"
    
    action = bpy.props.StringProperty()
    
    def execute(self, context): 
        city  = bpy.context.scene.CityName
        scale = bpy.context.scene.CityScale
        
        
        if city != "":
            bpy.ops.object.select_all(action='DESELECT')
        
            ob = bpy.data.objects.get(city)
            if ob != None:
                bpy.data.objects[city].select = True
                bpy.context.scene.objects.active = bpy.data.objects[city]
                bpy.context.object.scale[0] = scale
                bpy.context.object.scale[1] = scale
                bpy.context.object.scale[2] = scale
            
        return {'FINISHED'}

#*****************************#
#**#########################**#
#**#     Functions         #**#
#**#########################**#
#*****************************#

##########################
#   Generate Essentails  #
##########################      
def generateEssentials():
    
    #############
    # Objective #
    #############
    
    bpy.ops.object.select_all(action='DESELECT')
    ob = bpy.data.objects.get("Objective")
    if ob == None:
        bpy.ops.object.empty_add(location=(0,0,10),layers=(False,True,False,False,False,False,False,False,False,False,False,False,False,False,False,False,False,False,False,False))
        bpy.context.scene.layers[1] = True
        bpy.context.selected_objects[0].name = "Objective"
        bpy.ops.object.game_property_new(type='STRING',name="Objective")
        bpy.context.active_object.game.properties["Objective"].value = "Objective"
        bpy.context.scene.layers[1] = False
        bpy.context.scene.layers[0] = True
    
    ################
    # Game Manager #
    ################
    
    bpy.ops.object.select_all(action='DESELECT')
    
    ob = bpy.data.objects.get("GameManager")
    if ob == None:
        bpy.ops.object.empty_add(location=(100,100,100))#,layers=(False,True,False,False,False,False,False,False,False,False,False,False,False,False,False,False,False,False,False,False))
        #bpy.context.scene.layers[1] = True
        bpy.context.selected_objects[0].name = "GameManager"
        bpy.ops.object.game_property_new(type='FLOAT',name="prop")
        bpy.context.active_object.game.properties["prop"].value = 0
        
        if len(bpy.context.active_object.game.sensors) == 0:
            # LOGIC OBJECTS
                # SENSORS
            bpy.ops.logic.sensor_add(type='DELAY', name="Camera_SEN", object="")
            bpy.context.active_object.game.sensors['Camera_SEN'].use_pulse_true_level = False
            
                # CONTROLLERS
            bpy.ops.logic.controller_add(type='PYTHON', name="Camera_CONT", object="")
            bpy.context.active_object.game.controllers["Camera_CONT"].mode = "MODULE"
            bpy.context.active_object.game.controllers["Camera_CONT"].module = "Game.Camera"
            bpy.context.active_object.game.controllers["Camera_CONT"].link(bpy.context.active_object.game.sensors['Camera_SEN'])
    
    ########
    # Bomb #   
    ########
    
    bpy.ops.object.select_all(action='DESELECT')
    
    ob = bpy.data.objects.get("Bomb")
    if ob == None:
        bpy.ops.mesh.primitive_uv_sphere_add(location=(100,100,100),layers=(False,True,False,False,False,False,False,False,False,False,False,False,False,False,False,False,False,False,False,False))
        bpy.context.scene.layers[1] = True
        bpy.context.selected_objects[0].name = "Bomb"
        bpy.ops.object.game_property_new(type='STRING',name="Zombie")
        bpy.context.active_object.game.properties["Zombie"].value = "Zombie"
        
        if len(bpy.context.active_object.game.sensors) == 0:
            # LOGIC OBJECTS
                # SENSORS
            bpy.ops.logic.sensor_add(type='DELAY', name="Destroy Bomb_SEN", object="")
            bpy.context.active_object.game.sensors['Destroy Bomb_SEN'].use_pulse_true_level = False
            bpy.context.active_object.game.sensors['Destroy Bomb_SEN'].delay = 360
            
                # CONTROLLERS
            bpy.ops.logic.controller_add(type='PYTHON', name="Destroy Bomb_CONT", object="")
            bpy.context.active_object.game.controllers["Destroy Bomb_CONT"].mode = "MODULE"
            bpy.context.active_object.game.controllers["Destroy Bomb_CONT"].module = "Tools.DestroyBomb"
            bpy.context.active_object.game.controllers["Destroy Bomb_CONT"].link(bpy.context.active_object.game.sensors['Destroy Bomb_SEN'])
        
        bpy.context.scene.layers[1] = False
        bpy.context.scene.layers[0] = True
    
########################################
#   Generate pop marks  and objective  #
########################################      
def generatePopMark(type):
    
    NbZombie = bpy.context.scene.NbZombieMark
    NbHuman = bpy.context.scene.NbHumanMark
    
    bpy.context.scene.layers[0] = True
    
    if type == "human":
        i = 0
        
        while i < NbHuman:
            bpy.ops.object.empty_add(location=(i+1,2,10))
            bpy.context.selected_objects[0].name = "Pop_Human_Mark_"+str(i)
            i = i + 1
    elif type == "zombie":
        i = 0
        
        while i < NbZombie:
            bpy.ops.object.empty_add(location=(i+1,-2,10))
            bpy.context.selected_objects[0].name = "Pop_Zombie_Mark_"+str(i)
            i = i + 1
    
###################
#   Set camera    #
###################                           
def createCamera():
    bpy.ops.object.select_all(action='DESELECT')
    """
        ob = bpy.data.objects.get("Camera")
        if ob != None:
            bpy.data.objects["Camera"].select = True
            bpy.context.scene.objects.active = bpy.data.objects["Camera"]
            
            bpy.ops.object.delete()
        """    
    bpy.ops.object.camera_add(rotation=(90,0,0),location=(0,0,0))
    bpy.context.object.data.clip_end = 500
    bpy.context.object.data.clip_start = 0.01
    
    # LOGIC OBJECTS
        # SENSORS
    bpy.ops.logic.sensor_add(type='KEYBOARD', name="Forward_SEN", object="")
    bpy.context.active_object.game.sensors['Forward_SEN'].key = 'Z'
    
    bpy.ops.logic.sensor_add(type='KEYBOARD', name="Backward_SEN", object="")
    bpy.context.active_object.game.sensors['Backward_SEN'].key = 'S'
    
    bpy.ops.logic.sensor_add(type='KEYBOARD', name="Up_SEN", object="")
    bpy.context.active_object.game.sensors['Up_SEN'].key = 'A'
    
    bpy.ops.logic.sensor_add(type='KEYBOARD', name="Down_SEN", object="")
    bpy.context.active_object.game.sensors['Down_SEN'].key = 'E'
    
    bpy.ops.logic.sensor_add(type='KEYBOARD', name="Straff Right_SEN", object="")
    bpy.context.active_object.game.sensors['Straff Right_SEN'].key = 'D'
        
    bpy.ops.logic.sensor_add(type='KEYBOARD', name="Straff Left_SEN", object="")
    bpy.context.active_object.game.sensors['Straff Left_SEN'].key = 'Q'
    
    bpy.ops.logic.sensor_add(type='MOUSE', name="CameraControl_SEN", object="")
    bpy.context.active_object.game.sensors['CameraControl_SEN'].mouse_event = 'MOVEMENT'
    
        # CONTROLLERS
    bpy.ops.logic.controller_add(type='LOGIC_AND', name="Forward_CONT", object="")
    bpy.context.active_object.game.controllers["Forward_CONT"].link(bpy.context.active_object.game.sensors['Forward_SEN'])
    
    bpy.ops.logic.controller_add(type='LOGIC_AND', name="Backward_CONT", object="")
    bpy.context.active_object.game.controllers["Backward_CONT"].link(bpy.context.active_object.game.sensors['Backward_SEN'])
    
    bpy.ops.logic.controller_add(type='LOGIC_AND', name="Up_CONT", object="")
    bpy.context.active_object.game.controllers["Up_CONT"].link(bpy.context.active_object.game.sensors['Up_SEN'])
    
    bpy.ops.logic.controller_add(type='LOGIC_AND', name="Down_CONT", object="")
    bpy.context.active_object.game.controllers["Down_CONT"].link(bpy.context.active_object.game.sensors['Down_SEN'])
    
    bpy.ops.logic.controller_add(type='LOGIC_AND', name="Straff Right_CONT", object="")
    bpy.context.active_object.game.controllers["Straff Right_CONT"].link(bpy.context.active_object.game.sensors['Straff Right_SEN'])
    
    bpy.ops.logic.controller_add(type='LOGIC_AND', name="Straff Left_CONT", object="")
    bpy.context.active_object.game.controllers["Straff Left_CONT"].link(bpy.context.active_object.game.sensors['Straff Left_SEN'])
    
    bpy.ops.logic.controller_add(type='PYTHON', name="CameraControl_CONT", object="")
    bpy.context.active_object.game.controllers["CameraControl_CONT"].mode = "SCRIPT"
    bpy.context.active_object.game.controllers["CameraControl_CONT"].text = bpy.data.texts["CameraControl.py"]
    bpy.context.active_object.game.controllers["CameraControl_CONT"].link(bpy.context.active_object.game.sensors['CameraControl_SEN'])
        
        # ACTUATORS
    bpy.ops.logic.actuator_add(type='MOTION', name="Forward_ACT", object="")
    bpy.context.active_object.game.actuators['Forward_ACT'].mode = "OBJECT_NORMAL"
    bpy.context.active_object.game.actuators['Forward_ACT'].offset_location[2] = -1
    bpy.context.active_object.game.actuators['Forward_ACT'].use_local_location = True
    bpy.context.active_object.game.actuators['Forward_ACT'].link(bpy.context.active_object.game.controllers["Forward_CONT"])
    
    bpy.ops.logic.actuator_add(type='MOTION', name="Backward_ACT", object="")
    bpy.context.active_object.game.actuators['Backward_ACT'].mode = "OBJECT_NORMAL"
    bpy.context.active_object.game.actuators['Backward_ACT'].offset_location[2] = 1
    bpy.context.active_object.game.actuators['Backward_ACT'].use_local_location = True
    bpy.context.active_object.game.actuators['Backward_ACT'].link(bpy.context.active_object.game.controllers["Backward_CONT"])
    
    bpy.ops.logic.actuator_add(type='MOTION', name="Up_ACT", object="")
    bpy.context.active_object.game.actuators['Up_ACT'].mode = "OBJECT_NORMAL"
    bpy.context.active_object.game.actuators['Up_ACT'].offset_location[1] = 0.5
    bpy.context.active_object.game.actuators['Up_ACT'].use_local_location = True
    bpy.context.active_object.game.actuators['Up_ACT'].link(bpy.context.active_object.game.controllers["Up_CONT"])
    
    bpy.ops.logic.actuator_add(type='MOTION', name="Down_ACT", object="")
    bpy.context.active_object.game.actuators['Down_ACT'].mode = "OBJECT_NORMAL"
    bpy.context.active_object.game.actuators['Down_ACT'].offset_location[1] = -0.5
    bpy.context.active_object.game.actuators['Down_ACT'].use_local_location = True
    bpy.context.active_object.game.actuators['Down_ACT'].link(bpy.context.active_object.game.controllers["Down_CONT"])
        
    bpy.ops.logic.actuator_add(type='MOTION', name="Straff Right_ACT", object="")
    bpy.context.active_object.game.actuators['Straff Right_ACT'].mode = "OBJECT_NORMAL"
    bpy.context.active_object.game.actuators['Straff Right_ACT'].offset_location[0] = 0.5
    bpy.context.active_object.game.actuators['Straff Right_ACT'].use_local_location = True
    bpy.context.active_object.game.actuators['Straff Right_ACT'].link(bpy.context.active_object.game.controllers["Straff Right_CONT"])
    
    bpy.ops.logic.actuator_add(type='MOTION', name="Straff Left_ACT", object="")
    bpy.context.active_object.game.actuators['Straff Left_ACT'].mode = "OBJECT_NORMAL"
    bpy.context.active_object.game.actuators['Straff Left_ACT'].offset_location[0] = -0.5
    bpy.context.active_object.game.actuators['Straff Left_ACT'].use_local_location = True
    bpy.context.active_object.game.actuators['Straff Left_ACT'].link(bpy.context.active_object.game.controllers["Straff Left_CONT"])
    
    bpy.ops.logic.actuator_add(type='MOTION', name="LookUpDown_ACT", object="")
    bpy.context.active_object.game.actuators['LookUpDown_ACT'].mode = "OBJECT_NORMAL"
    bpy.context.active_object.game.actuators['LookUpDown_ACT'].use_local_location = True
    bpy.context.active_object.game.actuators['LookUpDown_ACT'].link(bpy.context.active_object.game.controllers["CameraControl_CONT"])
    
    bpy.ops.logic.actuator_add(type='MOTION', name="LookLeftRight_ACT", object="")
    bpy.context.active_object.game.actuators['LookLeftRight_ACT'].mode = "OBJECT_NORMAL"
    bpy.context.active_object.game.actuators['LookLeftRight_ACT'].use_local_location = True
    bpy.context.active_object.game.actuators['LookLeftRight_ACT'].link(bpy.context.active_object.game.controllers["CameraControl_CONT"])        
    
    bpy.context.scene.camera = bpy.data.objects["Camera"]
        
##################################
#   Set logic objects for BGE    #
##################################                           
def setCharacter(name, type):
    
    Run = bpy.context.scene.RunAnimationName
    Walk = bpy.context.scene.WalkAnimationName
    
    if name != "":
        bpy.ops.object.select_all(action='DESELECT')
    
        ob = bpy.data.objects.get(name)
        if ob != None:
            bpy.data.objects[name].select = True
            bpy.context.scene.objects.active = bpy.data.objects[name]
            
            #############
            # Character #
            #############
            
            #PHYSICS
            #bpy.data.objects[name].game.use_actor = True
            #
            bpy.context.object.game.physics_type = 'CHARACTER'
            bpy.context.object.game.use_actor = True
            
            # LOGIC OBJECTS
                # SENSORS
            bpy.ops.logic.sensor_add(type='ALWAYS', name="Steering_SEN", object="")
            bpy.context.active_object.game.sensors['Steering_SEN'].use_pulse_true_level = True
            bpy.context.active_object.game.sensors['Steering_SEN'].frequency = 100
            
            bpy.ops.logic.sensor_add(type='DELAY', name="CheckNavMesh_SEN", object="")
            bpy.context.active_object.game.sensors['CheckNavMesh_SEN'].use_pulse_true_level = False
            
            if type == "human":
                bpy.ops.logic.sensor_add(type='DELAY', name="Change Objective_SEN", object="")
                
                bpy.ops.logic.sensor_add(type='NEAR', name="Check Destination_SEN", object="")
                bpy.context.active_object.game.sensors['Check Destination_SEN'].property = "Objective"
                bpy.context.active_object.game.sensors['Check Destination_SEN'].distance = 10
                bpy.context.active_object.game.sensors['Check Destination_SEN'].reset_distance = 10
                bpy.context.active_object.game.sensors['Check Destination_SEN'].use_pulse_true_level = True
                bpy.context.active_object.game.sensors['Check Destination_SEN'].frequency = 200
                
                bpy.ops.logic.sensor_add(type='NEAR', name="Flee Zombie_SEN", object="")
                bpy.context.active_object.game.sensors['Flee Zombie_SEN'].property = "Zombie"
                bpy.context.active_object.game.sensors['Flee Zombie_SEN'].distance = 20
                bpy.context.active_object.game.sensors['Flee Zombie_SEN'].reset_distance = 30
                bpy.context.active_object.game.sensors['Flee Zombie_SEN'].use_pulse_true_level = True
                bpy.context.active_object.game.sensors['Flee Zombie_SEN'].frequency = 100
            
                bpy.ops.logic.sensor_add(type='NEAR', name="Get Infected_SEN", object="")
                bpy.context.active_object.game.sensors['Get Infected_SEN'].property = "Zombie"
                bpy.context.active_object.game.sensors['Get Infected_SEN'].distance = 1
                bpy.context.active_object.game.sensors['Get Infected_SEN'].reset_distance = 1
                bpy.context.active_object.game.sensors['Get Infected_SEN'].use_pulse_true_level = True
                bpy.context.active_object.game.sensors['Get Infected_SEN'].frequency = 100
                
                bpy.ops.logic.sensor_add(type='DELAY', name="Human Transformation_SEN", object="")
                bpy.context.active_object.game.sensors['Human Transformation_SEN'].use_pulse_true_level = True
                bpy.context.active_object.game.sensors['Human Transformation_SEN'].frequency = 200
            
            elif type == "zombie":
                bpy.ops.logic.sensor_add(type='NEAR', name="Get Closest Object_SEN", object="")
                bpy.context.active_object.game.sensors['Get Closest Object_SEN'].property = "Human"
                bpy.context.active_object.game.sensors['Get Closest Object_SEN'].distance = 20
                bpy.context.active_object.game.sensors['Get Closest Object_SEN'].reset_distance = 30
                bpy.context.active_object.game.sensors['Get Closest Object_SEN'].use_pulse_true_level = True
                bpy.context.active_object.game.sensors['Get Closest Object_SEN'].frequency = 100
                
                # CONTROLLERS
            bpy.ops.logic.controller_add(type='LOGIC_AND', name="And_CONT", object="")
            bpy.context.active_object.game.controllers["And_CONT"].link(bpy.context.active_object.game.sensors['Steering_SEN'])

            bpy.ops.logic.controller_add(type='PYTHON', name="CheckNavMesh_CONT", object="")
            bpy.context.active_object.game.controllers["CheckNavMesh_CONT"].mode = "MODULE"
            bpy.context.active_object.game.controllers["CheckNavMesh_CONT"].module = "Tools.CheckNavMesh"
            bpy.context.active_object.game.controllers["CheckNavMesh_CONT"].use_priority = True
            bpy.context.active_object.game.controllers["CheckNavMesh_CONT"].link(bpy.context.active_object.game.sensors['CheckNavMesh_SEN'])
            
            if type == "human":
                bpy.ops.logic.controller_add(type='PYTHON', name="Change Objective_CONT", object="")
                bpy.context.active_object.game.controllers["Change Objective_CONT"].mode = "MODULE"
                bpy.context.active_object.game.controllers["Change Objective_CONT"].module = "Tools.ChangeObjective"
                bpy.context.active_object.game.controllers["Change Objective_CONT"].link(bpy.context.active_object.game.sensors['Change Objective_SEN'])
                
                bpy.ops.logic.controller_add(type='PYTHON', name="Check Destination_CONT", object="")
                bpy.context.active_object.game.controllers["Check Destination_CONT"].mode = "MODULE"
                bpy.context.active_object.game.controllers["Check Destination_CONT"].module = "Tools.CheckDestination"
                bpy.context.active_object.game.controllers["Check Destination_CONT"].link(bpy.context.active_object.game.sensors['Check Destination_SEN'])
                
                bpy.ops.logic.controller_add(type='PYTHON', name="Flee Zombie_CONT", object="")
                bpy.context.active_object.game.controllers["Flee Zombie_CONT"].mode = "MODULE"
                bpy.context.active_object.game.controllers["Flee Zombie_CONT"].module = "Tools.FleeZombie"
                bpy.context.active_object.game.controllers["Flee Zombie_CONT"].link(bpy.context.active_object.game.sensors['Flee Zombie_SEN'])
                
                bpy.ops.logic.controller_add(type='PYTHON', name="Get Infected_CONT", object="")
                bpy.context.active_object.game.controllers["Get Infected_CONT"].mode = "MODULE"
                bpy.context.active_object.game.controllers["Get Infected_CONT"].module = "Tools.GetInfected"
                bpy.context.active_object.game.controllers["Get Infected_CONT"].link(bpy.context.active_object.game.sensors['Get Infected_SEN'])
                
                bpy.ops.logic.controller_add(type='PYTHON', name="Human Transformation_CONT", object="")
                bpy.context.active_object.game.controllers["Human Transformation_CONT"].mode = "MODULE"
                bpy.context.active_object.game.controllers["Human Transformation_CONT"].module = "Tools.HumanTransformation"
                bpy.context.active_object.game.controllers["Human Transformation_CONT"].link(bpy.context.active_object.game.sensors['Human Transformation_SEN'])
            
            elif type == "zombie":
                bpy.ops.logic.controller_add(type='PYTHON', name="Get Closest Object_CONT", object="")
                bpy.context.active_object.game.controllers["Get Closest Object_CONT"].mode = "MODULE"
                bpy.context.active_object.game.controllers["Get Closest Object_CONT"].module = "Tools.GetClosestObject"
                bpy.context.active_object.game.controllers["Get Closest Object_CONT"].link(bpy.context.active_object.game.sensors['Get Closest Object_SEN'])
                
            
                # ACTUATORS
            bpy.ops.logic.actuator_add(type='STEERING', name="Steering_ACT", object="")
            bpy.context.active_object.game.actuators['Steering_ACT'].mode = "PATHFOLLOWING"
            
            if type == "human":
                bpy.context.active_object.game.actuators['Steering_ACT'].distance = 2.5
                bpy.context.active_object.game.actuators['Steering_ACT'].velocity = 1
            elif type == "zombie":
                bpy.context.active_object.game.actuators['Steering_ACT'].distance = 1
                bpy.context.active_object.game.actuators['Steering_ACT'].velocity = 3
                
            bpy.context.active_object.game.actuators['Steering_ACT'].acceleration = 30
            bpy.context.active_object.game.actuators['Steering_ACT'].turn_speed = 120
            bpy.context.active_object.game.actuators['Steering_ACT'].facing = True
            bpy.context.active_object.game.actuators['Steering_ACT'].facing_axis = "NEG_Y"
            bpy.context.active_object.game.actuators['Steering_ACT'].update_period = 200
            bpy.context.active_object.game.actuators['Steering_ACT'].normal_up = True
            bpy.context.active_object.game.actuators['Steering_ACT'].link(bpy.context.active_object.game.controllers["And_CONT"])
            bpy.context.active_object.game.actuators['Steering_ACT'].link(bpy.context.active_object.game.controllers["CheckNavMesh_CONT"])
            
            if type == "human":
                bpy.context.active_object.game.actuators['Steering_ACT'].link(bpy.context.active_object.game.controllers["Change Objective_CONT"])
                bpy.context.active_object.game.actuators['Steering_ACT'].link(bpy.context.active_object.game.controllers["Check Destination_CONT"])
                bpy.context.active_object.game.actuators['Steering_ACT'].link(bpy.context.active_object.game.controllers["Flee Zombie_CONT"])
                bpy.context.active_object.game.actuators['Steering_ACT'].link(bpy.context.active_object.game.controllers["Get Infected_CONT"])
            
            elif type == "zombie":
                bpy.context.active_object.game.actuators['Steering_ACT'].link(bpy.context.active_object.game.controllers["Get Closest Object_CONT"])
                
                #PROPERTIES
            
            if type == "human":
                bpy.ops.object.game_property_new(type='BOOL',name="human")
                bpy.context.active_object.game.properties["human"].value = True
                
                bpy.ops.object.game_property_new(type='BOOL',name="Infected")
                bpy.context.active_object.game.properties["Infected"].value = False
                
                bpy.ops.object.game_property_new(type='STRING',name="Human")
                bpy.context.active_object.game.properties["Human"].value = "Human"
                
                bpy.ops.object.game_property_new(type='INT',name="Panic")
                bpy.context.active_object.game.properties["Panic"].value = 0
                
                bpy.ops.object.game_property_new(type='FLOAT',name="Velocity")
                bpy.context.active_object.game.properties["Velocity"].value = 1
            elif type == "zombie":
                bpy.ops.object.game_property_new(type='BOOL',name="zombie")
                bpy.context.active_object.game.properties["zombie"].value = True
                
                bpy.ops.object.game_property_new(type='STRING',name="Zombie")
                bpy.context.active_object.game.properties["Zombie"].value = "Zombie"
            ############
            # Armature #
            ############
            
            arm = bpy.data.objects[name].children[0]
            bpy.ops.object.select_all(action='DESELECT')
            arm.select = True
            bpy.context.scene.objects.active = arm
            
            if Run != "" and Walk != "":
                # LOGIC OBJECTS
                    # SENSORS
                bpy.ops.logic.sensor_add(type='ALWAYS', name="Always_SEN", object="")
                bpy.context.active_object.game.sensors['Always_SEN'].use_pulse_true_level = True
                bpy.context.active_object.game.sensors['Always_SEN'].frequency = 200
                
                    # CONTROLLERS
                bpy.ops.logic.controller_add(type='LOGIC_AND', name="And_CONT", object="")
                bpy.context.active_object.game.controllers["And_CONT"].link(bpy.context.active_object.game.sensors['Always_SEN'])
                
                    # ACTUATORS
                bpy.ops.logic.actuator_add(type='ACTION', name="Action_ACT", object="")
                bpy.context.active_object.game.actuators['Action_ACT'].play_mode = "LOOPEND"
                bpy.context.active_object.game.actuators['Action_ACT'].frame_start = 1
                bpy.context.active_object.game.actuators['Action_ACT'].frame_blend_in = 5
                bpy.context.active_object.game.actuators['Action_ACT'].priority = 2
                
                if type == "zombie":
                    bpy.context.active_object.game.actuators['Action_ACT'].action = bpy.data.actions[Run]
                    bpy.context.active_object.game.actuators['Action_ACT'].frame_property = Run
                    bpy.context.active_object.game.actuators['Action_ACT'].frame_end = 20
                elif type == "human":
                    bpy.context.active_object.game.actuators['Action_ACT'].action = bpy.data.actions[Walk]
                    bpy.context.active_object.game.actuators['Action_ACT'].frame_property = Walk
                    bpy.context.active_object.game.actuators['Action_ACT'].frame_end = 40
                
                
                bpy.context.active_object.game.actuators['Action_ACT'].link(bpy.context.active_object.game.controllers["And_CONT"])
                
                    #PROPERTIES
                bpy.ops.object.game_property_new(type='FLOAT',name="prop")
                bpy.context.active_object.game.properties["prop"].value = 0
                
                bpy.ops.object.game_property_new(type='FLOAT',name="Idle")
                bpy.context.active_object.game.properties["Idle"].value = 0
                
                bpy.ops.object.game_property_new(type='FLOAT',name="Walk")
                bpy.context.active_object.game.properties["Walk"].value = 0
                
                bpy.ops.object.game_property_new(type='FLOAT',name="Run")
                bpy.context.active_object.game.properties["Run"].value = 0
                
                bpy.ops.object.game_property_new(type='FLOAT',name="Jump")
                bpy.context.active_object.game.properties["Jump"].value = 0
            
#    Registration
bpy.utils.register_module(__name__)